package net.lucamasini.ricette.client.ricette;

import static net.lucamasini.ricette.client.ServiceBus.getEventbus;

import java.util.*;

import net.lucamasini.ricette.client.ClientFactory;
import net.lucamasini.ricette.client.ingredienti.IngredienteProxy;
import net.lucamasini.ricette.client.ingredienti.event.NewListaIngredientiEvent;
import net.lucamasini.ricette.client.ingredienti.event.RefreshListaIngredientiEvent;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.place.shared.Place;
import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

public class RicetteDialogActivity extends AbstractActivity implements  NewListaIngredientiEvent.Handler, RicetteDialogView.Presenter {

	interface RicetteDriver extends RequestFactoryEditorDriver<RicettaProxy, RicetteDialog> {}
	private RicetteDriver driver = GWT.create(RicetteDriver.class);
	private final RicetteDialogView view;
		
	private final ClientFactory clientFactory;
	private RicetteRequest currentContext;
	
	private Map<String, IngredienteProxy> cachedIngredientiMap;
	private List<IngredienteProxy> cachedIngredientiList;
	private RicettaProxy ricetta;
	private final EntityProxyId<? extends RicettaProxy> entityProxyId;
	
	private HandlerRegistration handlerListaIngredienti;
	
	public RicetteDialogActivity(EntityProxyId<? extends RicettaProxy> entityProxyId, ClientFactory clientFactory) {
		this.clientFactory = clientFactory;
		this.view = clientFactory.getRicetteDialogView();
		this.view.setPresenter(this);
		this.entityProxyId = entityProxyId;
		
		
		driver.initialize((RicetteDialog) view.asWidget());
	}

	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		
		this.handlerListaIngredienti = getEventbus().addHandler(NewListaIngredientiEvent.TYPE, this);
		
		if( entityProxyId!=null ) {
			clientFactory.getRequestFactory().find(entityProxyId).with("ingredientiRicetta").to(new Receiver<RicettaProxy>() {
				@Override
				public void onSuccess(RicettaProxy response) {
					getEventbus().fireEvent(new RefreshListaIngredientiEvent(true));
					
					modificaRicetta(response);
				}
			}).fire();
		} else {
			creaRicetta();
		}
	}

	@Override
	public void onStop() {
		handlerListaIngredienti.removeHandler();
	}
	
	private RicetteRequest ricetta() {
		
		RicetteRequest context = (RicetteRequest) driver.flush();
	    
		if (driver.hasErrors()) {
			Window.alert(driver.getErrors().toString());
			
			return null;
	    }
		
		return context;
	}

	private void setRicetta(RicettaProxy ricetta, RequestContext context) {
		
		this.ricetta = ricetta;
		
		driver.edit(ricetta, context);
		
		view.showAndCenter();
	}
	
	void updateContext() {
		currentContext = clientFactory.getRequestFactory().ricetteRequest();
	}

	public void creaRicetta() {
		updateContext();
		final RicettaProxy r = currentContext.create(RicettaProxy.class);
		r.setIngredientiRicetta(new ArrayList<IngredientiRicettaProxy>());
		modificaRicetta(r, currentContext);
	}

	public void modificaRicetta(RicettaProxy i) {
		updateContext();
		modificaRicetta(i, currentContext);
	}
	
	public void modificaRicetta(RicettaProxy i, RequestContext context) {
		setRicetta(i, context);
		
		refreshCellTableIngredienti();
		refreshCellTableIngredientiRicetta();
	}

	@Override
	public void goTo(Place place) {
		clientFactory.getPlaceController().goTo(place);
	}

	@Override
	public void salvaRicetta() {
		ricetta().salvaRicetta(ricetta, ricetta.getIngredientiRicetta()).with("ingredientiRicetta").fire(new Receiver<Void>() {

			@Override
			public void onSuccess(Void response) {
				view.hide();
				goTo(new RicettePlace());
			}
			
		}); 		
	}
	
	private void refreshCellTableIngredienti() {
		if( cachedIngredientiMap!=null && ricetta !=null ) {
			view.fromDataProvider().setList(cachedIngredientiList);
			view.clearIngredientiSelection();
		} else {
			getEventbus().fireEvent(new RefreshListaIngredientiEvent(true));
		}
	}

	private void refreshCellTableIngredientiRicetta() {
		if( cachedIngredientiMap!=null) {
			view.toDataProvider().setList(ricetta.getIngredientiRicetta());
			view.clearIngredientiRicettaSelection();
		} else {
			getEventbus().fireEvent(new RefreshListaIngredientiEvent(true));
		}
	}

	@Override
	public void onNewListaIngredientiResponse(NewListaIngredientiEvent event) {
		List<IngredienteProxy> result = event.getListaIngredienti();
		
		cachedIngredientiList = result;
		cachedIngredientiMap = new HashMap<String, IngredienteProxy>();
		for(IngredienteProxy i: result) {
			cachedIngredientiMap.put(i.getId(), i);
		}
		refreshCellTableIngredienti();
		refreshCellTableIngredientiRicetta();
	}

	@Override
	public void addIngrediente(IngredienteProxy ingrediente) {
		if( ingrediente!=null) {
			
			IngredientiRicettaProxy ir = currentContext.create(IngredientiRicettaProxy.class);
			ir.setKeyIngrediente(ingrediente.getId());
			
			ricetta.getIngredientiRicetta().add(ir);
			refreshCellTableIngredienti();
			refreshCellTableIngredientiRicetta();
		}
	}

	@Override
	public void removeIngrediente(IngredientiRicettaProxy ir) {
		if( ir!=null) {
			for(Iterator<IngredientiRicettaProxy> iter=ricetta.getIngredientiRicetta().iterator();iter.hasNext();) {
				IngredientiRicettaProxy current = iter.next();
				if( current.stableId().equals(ir.stableId())) {
					iter.remove();
					break;
				}
			}
			refreshCellTableIngredienti();
			refreshCellTableIngredientiRicetta();
		}
	}	
	
	@Override
	public String decodeIngrediente(IngredientiRicettaProxy ir){
		if( cachedIngredientiMap!=null ) {
			return cachedIngredientiMap.containsKey(ir.getKeyIngrediente())?cachedIngredientiMap.get(ir.getKeyIngrediente()).getDescrizione():"ND";	
		} else {
			return "NA";
		}
		
	}
}
